﻿// Decompiled with JetBrains decompiler
// Type: Netick.NetworkLinkedListSnapshot`1
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System.Collections;
using System.Collections.Generic;

#nullable disable
namespace Netick;

/// <summary>
/// A snapshot of the state of a <see cref="T:Netick.NetworkLinkedList`1" /> collection. Note this must not be used outside the scope of an OnChanged call or a NetworkRender call.
/// </summary>
public struct NetworkLinkedListSnapshot<T> : IEnumerable<T>, IEnumerable where T : unmanaged
{
  private unsafe int* Ptr;
  private int _linkedListItemSizeWords;

  private unsafe int HeadNode => *this.Ptr;

  private unsafe int TailNode => this.Ptr[1];

  private unsafe int FreeTail => this.Ptr[2];

  public unsafe int Count => this.Ptr[3];

  /// <summary>Gets the first node in the linked list snapshot.</summary>
  public NetworkLinkedListNode<T> Head
  {
    get
    {
      if (this.HeadNode != -1)
        return this.GetNode(this.HeadNode);
      return new NetworkLinkedListNode<T>()
      {
        Index = -1,
        Next = -1,
        Previous = -1
      };
    }
  }

  /// <summary>Gets the last node in the linked list snapshot.</summary>
  public NetworkLinkedListNode<T> Tail
  {
    get
    {
      if (this.TailNode != -1)
        return this.GetNode(this.TailNode);
      return new NetworkLinkedListNode<T>()
      {
        Index = -1,
        Next = -1,
        Previous = -1
      };
    }
  }

  /// <summary>Gets the node at the specified index in the snapshot.</summary>
  public NetworkLinkedListNode<T> GetNode(int index)
  {
    InternalNetworkLinkedListElement elementMeta = this.GetElementMeta(index);
    return new NetworkLinkedListNode<T>()
    {
      Item = this.GetElementData(index),
      Index = index,
      Previous = elementMeta.Previous,
      Next = elementMeta.Next
    };
  }

  private unsafe T GetElementData(int index)
  {
    return *(T*) (this.Ptr + 4 + index * this._linkedListItemSizeWords + 2);
  }

  private unsafe InternalNetworkLinkedListElement GetElementMeta(int index)
  {
    return *(InternalNetworkLinkedListElement*) (this.Ptr + 4 + index * this._linkedListItemSizeWords);
  }

  internal unsafe NetworkLinkedListSnapshot(int* p)
  {
    this.Ptr = p;
    this._linkedListItemSizeWords = NetickUtils.GetWordSize(sizeof (InternalNetworkLinkedListElement) + sizeof (T));
  }

  public IEnumerator<T> GetEnumerator()
  {
    for (int cur = this.HeadNode; cur != -1; cur = this.GetElementMeta(cur).Next)
      yield return this.GetElementData(cur);
  }

  IEnumerator IEnumerable.GetEnumerator() => (IEnumerator) this.GetEnumerator();
}
